Passed
Push — master ( 63524c...dd4398 )
by Night
01:10
created

stringFuncs.indexOfLastAny   A

Complexity

Conditions 4
Paths 6

Size

Total Lines 25
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 4
eloc 11
nc 6
nop 3
dl 0
loc 25
rs 9.85
c 0
b 0
f 0
1
/** global: UB */
2
3
var stringFuncs = {
4
	
5
	
6
	// primary search functions
7
	indexOf: function(search, startAt = null){
8
		return this.smartIndexOf(search, true, true, startAt);
9
	},
10
	indexOfCI: function(search, startAt = null){
11
		return this.smartIndexOf(search, false, true, startAt);
12
	},
13
	smartIndexOf: function(search, caseSensitive = true, first = true, startAt = null, substringIsLower = false, wholeWords = false){
14
		var text = this;
15
		
16
		// temps
17
		var sl = search.length;
18
		var ml = (text.length - sl);
19
		
20
		// quick checks
21
		if (ml < sl) {
22
			return -1;
23
		}
24
		
25
		// only check equality of both strings of equal length
26
		if (ml == sl) {
27
			if (caseSensitive && !wholeWords) {
28
				return (text == search) ? 0 : -1;
29
			}
30
			return text.isEqual(search, caseSensitive, false, substringIsLower) ? 0 : -1;
31
		}
32
		
33
		
34
		// default start at
35
		if (first) {
36
			if (startAt == null) {
1 ignored issue
show
Best Practice introduced by
Comparing startAt to null using the == operator is not safe. Consider using === instead.
Loading history...
37
				startAt = 0;
38
			}
39
		} else {
40
			if (startAt == null) {
41
				startAt = ml - sl;
42
			}
43
		}
44
		
45
		
46
		// if using whole words, slower version is used
47
		if (wholeWords) {
48
			var regex = UB.regex.New(search, wholeWords, caseSensitive, true);
49
			if (first) {
50
				var i = startAt == 0 ? text.search(regex) : text.substring(startAt).search(regex);
51
			} else {
52
				/*var i:int = startAt == (ml - sl) ? text.search(regex) : text.substring(startAt).search(regex);*/
53
				/// unsupported
54
				i = -1;
55
			}
56
			return i;
57
		}
58
		
59
		
60
		
61
		if (first) {
62
			
63
			//---------------------------------------------
64
			// FIRST INDEX
65
			
66
			// CASE INSENSITIVE
67 View Code Duplication
			if (!caseSensitive) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
68
				
69
				// init casing tables
70
				if (UB.UTF_lowerToUpper == null){
1 ignored issue
show
Best Practice introduced by
Comparing UB.UTF_lowerToUpper to null using the == operator is not safe. Consider using === instead.
Loading history...
71
					UB.initCasing();
72
				}
73
				
74
				
75
				// very fast CI comparison
76
				
77
				// per main char
78
				for (var m = startAt;m <= ml;m++){
79
					
80
					
81
					// per substring char
82
					var match = true;
83
					for (var s = 0;s<sl;s++){
84
						
85
						var c1 = text.charCodeAt(m + s);
86
						var c2 = search.charCodeAt(s);
87
						
88
						// CI
89
						if (c1 <= UB.UTF_casingTablesMax){ /// CI
90
							c1 = UB.UTF_upperToLower[c1];
91
						}
92
						if (!substringIsLower){
93
							if (c2 <= UB.UTF_casingTablesMax){ /// CI
94
								c2 = UB.UTF_upperToLower[c2];
95
							}
96
						}
97
						
98
						if (c1 != c2) {
99
							match = false;
100
							break;
101
						}
102
						
103
					}
104
					
105
					if (match){
106
						return m;
107
					}
108
					
109
				}
110
				
111
				return -1;
112
				
113
				
114
				//return text.toUpperCase().indexOf(search.toUpperCase(), startAt);
115
			}
116
			
117
			// CASE SENSITIVE
118
			return text.indexOf(search, startAt);
119
			
120
		}else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
121
			
122
			//---------------------------------------------
123
			// LAST INDEX
124
			
125
			// CASE INSENSITIVE
126 View Code Duplication
			if (!caseSensitive) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
127
				
128
				// init casing tables
129
				if (UB.UTF_lowerToUpper == null){
130
					UB.initCasing();
131
				}
132
				
133
				
134
				// very fast CI comparison
135
				
136
				// per main char
137
				for (var m = startAt;m >= 0;m--){
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable m already seems to be declared on line 78. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
138
					
139
					
140
					// per substring char
141
					match = true;
142
					for (var s = 0;s<sl;s++){
0 ignored issues
show
Comprehensibility Naming Best Practice introduced by
The variable s already seems to be declared on line 83. Consider using another variable name or omitting the var keyword.

This check looks for variables that are declared in multiple lines. There may be several reasons for this.

In the simplest case the variable name was reused by mistake. This may lead to very hard to locate bugs.

If you want to reuse a variable for another purpose, consider declaring it at or near the top of your function and just assigning to it subsequently so it is always declared.

Loading history...
143
						
144
						c1 = text.charCodeAt(m + s);
145
						c2 = search.charCodeAt(s);
146
						
147
						// CI
148
						if (c1 <= UB.UTF_casingTablesMax){ /// CI
149
							c1 = UB.UTF_upperToLower[c1];
150
						}
151
						if (!substringIsLower){
152
							if (c2 <= UB.UTF_casingTablesMax){ /// CI
153
								c2 = UB.UTF_upperToLower[c2];
154
							}
155
						}
156
						
157
						if (c1 != c2) {
158
							match = false;
159
							break;
160
						}
161
						
162
					}
163
					
164
					if (match){
165
						return m;
166
					}
167
					
168
				}
169
				
170
				return -1;
171
			}
172
			
173
			// CASE SENSITIVE
174
			return text.lastIndexOf(search, startAt);
175
		}
176
	},
177
	countOf: function(find, caseSensitive = true){
178
		var text = this;
179
		
180
		// use regex method for case insensitive comparison
181
		if (!caseSensitive){
182
			var char = UB.regex.Escape(find);
183
			var flags = 'ig';
184
			return parseInt(text.match(new RegExp(char, flags)).length);
185
		}
186
		
187
		// use faster method for case sensitive comparison
188
		var count = 0;
189
		var index = 0;
190
		var len = find.length;
191
		while ((index = text.indexOf(find, index)) > -1) {
192
			count++;
193
			index += len;
194
		}
195
		return count;
196
	},
197
	
198
	/** searches for all the given terms, collects their char indexes (S.IndexOf), and returns the smallest/largest index (depending on `first`) */
199
	indexOfAny: function(searchFor, first = true, caseSensitive = true, startAt = null){
200
		var str = this;
201
		if (first) {
202
			return str.indexOfFirstAny(searchFor, caseSensitive, startAt);
203
		} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
204
			if (startAt == null) {
1 ignored issue
show
Best Practice introduced by
Comparing startAt to null using the == operator is not safe. Consider using === instead.
Loading history...
205
				startAt = 0;
206
			}
207
			return str.indexOfLastAny(searchFor, caseSensitive, startAt);
208
		}
209
	},
210
	/** searches for all the given terms, collects their char indexes (S.IndexOf), and returns the largest index */
211
	indexOfLastAny: function(searchFor, caseSensitive = true, startAt = null){
212
		var str = this;
213
		
214
		// case insensitive if wanted
215
		if (!caseSensitive){
216
			str = str.toLowerCase();
217
		}
218
		
219
		// per search term
220
		var indices = [];
221
		for (var s = 0, sl = searchFor.length;s<sl;s++){
222
			var sWord = searchFor[s];
223
			
224
			// case insensitive if wanted
225
			if (!caseSensitive){
226
				sWord = sWord.toLowerCase();
227
			}
228
			
229
			// check where found
230
			indices[s] = str.lastIndexOf(sWord, startAt);
231
		}
232
		
233
		// return last found term
234
		return indices.max();
235
	},
236
	/** searches for all the given terms, collects their char indexes (S.IndexOf), and returns the smallest index */
237
	indexOfFirstAny: function(searchFor, caseSensitive = true, startAt = 0){
238
		var str = this;
239
		
240
		// case insensitive if wanted
241
		if (!caseSensitive){
242
			str = str.toLowerCase();
243
		}
244
		
245
		// per search term
246
		var indices = [];
247
		for (var s = 0, sl = searchFor.length;s<sl;s++){
248
			var sWord = searchFor[s];
249
			
250
			// case insensitive if wanted
251
			if (!caseSensitive){
252
				sWord = sWord.toLowerCase();
253
			}
254
			
255
			// check where found
256
			indices[s] = str.indexOf(sWord, startAt);
257
			
258
			// change -1 otherwise looks like first found term
259
			if (indices[s] == -1) {
260
				indices[s] = int.MAX_VALUE;
0 ignored issues
show
Bug introduced by
The variable int seems to be never declared. If this is a global, consider adding a /** global: int */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
261
			}
262
		}
263
		
264
		// return first found term
265
		return N1D.Min(indices);
0 ignored issues
show
Bug introduced by
The variable N1D seems to be never declared. If this is a global, consider adding a /** global: N1D */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
266
	},
267
	endIndexOfLastAny: function(searchFor, caseSensitive = true){
268
		var str = this;
269
		
270
		// case insensitive if wanted
271
		if (!caseSensitive){
272
			str = str.toLowerCase();
273
		}
274
		
275
		// per search term
276
		var indices = [];
277
		for (var s = 0, sl = searchFor.length;s<sl;s++){
278
			var sWord = searchFor[s];
279
			
280
			// case insensitive if wanted
281
			if (!caseSensitive){
282
				sWord = sWord.toLowerCase();
283
			}
284
			
285
			// check where found
286
			indices[s] = S.endIndexOfLast(str, sWord);
0 ignored issues
show
Bug introduced by
The variable S seems to be never declared. If this is a global, consider adding a /** global: S */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
287
		}
288
		
289
		// return last found term
290
		return N1D.Max(indices);
0 ignored issues
show
Bug introduced by
The variable N1D seems to be never declared. If this is a global, consider adding a /** global: N1D */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
291
	},
292
	endIndexOfFirstAny: function(searchFor, caseSensitive = true){
293
		var str = this;
294
		
295
		// case insensitive if wanted
296
		if (!caseSensitive){
297
			str = str.toLowerCase();
298
		}
299
		
300
		// per search term
301
		var indices = [];
302
		for (var s = 0, sl = searchFor.length;s<sl;s++){
303
			var sWord = searchFor[s];
304
			
305
			// case insensitive if wanted
306
			if (!caseSensitive){
307
				sWord = sWord.toLowerCase();
308
			}
309
			
310
			// check where found
311
			indices[s] = S.endIndexOfFirst(str, sWord);
0 ignored issues
show
Bug introduced by
The variable S seems to be never declared. If this is a global, consider adding a /** global: S */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
312
			
313
			// change -1 otherwise looks like first found term
314
			if (indices[s] == -1) {
315
				indices[s] = int.MAX_VALUE;
0 ignored issues
show
Bug introduced by
The variable int seems to be never declared. If this is a global, consider adding a /** global: int */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
316
			}
317
		}
318
		
319
		// return first found term
320
		return N1D.Min(indices);
0 ignored issues
show
Bug introduced by
The variable N1D seems to be never declared. If this is a global, consider adding a /** global: N1D */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
321
	},
322
	endIndexOfFirst: function(find){
323
		var str = this;
324
		var pos = str.indexOf(find);
325
		if (pos == -1) return -1;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
326
		return pos + find.length;
327
	},
328
	endIndexOfLast: function(find){
329
		var str = this;
330
		var pos = str.lastIndexOf(find);
331
		if (pos == -1) return -1;
0 ignored issues
show
Coding Style Best Practice introduced by
Curly braces around statements make for more readable code and help prevent bugs when you add further statements.

Consider adding curly braces around all statements when they are executed conditionally. This is optional if there is only one statement, but leaving them out can lead to unexpected behaviour if another statement is added later.

Consider:

if (a > 0)
    b = 42;

If you or someone else later decides to put another statement in, only the first statement will be executed.

if (a > 0)
    console.log("a > 0");
    b = 42;

In this case the statement b = 42 will always be executed, while the logging statement will be executed conditionally.

if (a > 0) {
    console.log("a > 0");
    b = 42;
}

ensures that the proper code will be executed conditionally no matter how many statements are added or removed.

Loading history...
332
		return pos + find.length;
333
	},
334
	indexOfNumber: function(startAt = 0, not = false, lenIfNotFound = false){
335
		var str = this;
336
		for (var c = (startAt>0?startAt:0), cl = str.length;c<cl;c++){
337
			var char = str.charAt(c);
338
			if (char.sNumber(i) != not) {
0 ignored issues
show
Bug introduced by
The variable i seems to be never declared. If this is a global, consider adding a /** global: i */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
339
				return c;
340
			}
341
		}
342
		return lenIfNotFound ? str.length : -1;
343
	},
344
	indexOfAlphaNumeric: function(startAt = 0, not = false, lenIfNotFound = false){
345
		var str = this;
346
		for (var c = (startAt>0?startAt:0), cl = str.length;c<cl;c++){
347
			var char = str.charAt(c);
348
			if (char.isAlphaNumeric() != not) {
349
				return c;
350
			}
351
		}
352
		return lenIfNotFound ? str.length : -1;
353
	},
354
	
355
	indexOfMany: function(find, startAt = 0){
356
		var str = this;
357
		
358
		// returns the index, of the FIRST FOUND item in the string
359
		
360
		var found = -1;
361
		for (var f = 0, fl = find.length;f<fl;f++){
362
			var at = str.indexOf(find[f], startAt);
363
			if (at != -1 && (at < found || found == -1)) {
364
				found = at;
365
			}
366
		}
367
		return found;
368
	},
369
	
370
	
371
	indexOfAll: function(find, caseSensitive = true, startAt = 0, wholeWords = false){
372
		var str = this;
373
		var indices = [];
374
		
375
		var len = str.length;
376
		var c = startAt;
377
		while (c < len) {
378
			c = S.IndexOf(str, find, caseSensitive, true, c, false, wholeWords);
0 ignored issues
show
Bug introduced by
The variable S seems to be never declared. If this is a global, consider adding a /** global: S */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
379
			if (c == -1) {
380
				break;
381
			}
382
			indices.push(c);
383
			c += find.length;
384
		}
385
		
386
		return indices;
387
	},
388
	
389
	none:null
390
};
391
392
// register funcs
393
UB.registerFuncs(String.prototype, stringFuncs);